package pl.softech.demo2d.physics.fluid.grid;

import pl.softech.demo2d.physics.fluid.grid.Cell.Flag;

/**
 * @formatter:off
 * f = fluid
 * s = surface cell
 * e = empty 
 * 
 */
public enum Surface implements ISurface {
	
	/** 
	 * Południe
	 * 
	 *   f
	 *   |
	 * f-s-f
	 *   |
	 *   e
	 */
	//@formatter:on
	S(_S) {

		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j - 1].v = cells[i][j].v + dy / dx * (cells[i][j].u - cells[i - 1][j].u);
		}

	},
	//@formatter:off
	/** 
	 * Zachód
	 * 
	 *   f
	 *   |
	 * e-s-f
	 *   |
	 *   f
	 *    
	 */
	W(_W) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i - 1][j].u = cells[i][j].u + dx / dy * (cells[i][j].v - cells[i][j - 1].v);
		}
		//@formatter:off
	},
	/** 
	 * Północ
	 * 
	 *   e
	 *   |
	 * f-s-f
	 *   |
	 *   f
	 */
	N(_N) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].v = cells[i][j - 1].v + dy / dx * (cells[i - 1][j].u - cells[i][j].u);
		}
		//@formatter:off
	},
	/** 
	 * Wschód
	 * 
	 *   f
	 *   |
	 * f-s-e
	 *   |
	 *   f
	 *  
	 */
	E(_E) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].u = cells[i - 1][j].u - dx / dy * (cells[i][j].v - cells[i][j - 1].v);
		}
		//@formatter:off
	},
	
	/** 
	 * Południe - Zachód
	 * 
	 *   f
	 *   |
	 * f-s-e
	 *   |
	 *   e
	 *  
	 */
	SE((byte)(_S+_E)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].u = cells[i - 1][j].u;
			cells[i][j - 1].v = cells[i][j].v;

		}
		//@formatter:off
	},
	
	/** 
	 * Południe - Wschód
	 * 
	 *   f
	 *   |
	 * e-s-f
	 *   |
	 *   e
	 *  
	 */
	SW((byte)(_S+_W)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i - 1][j].u = cells[i][j].u;
			cells[i][j - 1].v = cells[i][j].v;
		}
		//@formatter:off
	},
	
	/** 
	 * Północ - Zachód
	 * 
	 *   e
	 *   |
	 * e-s-f
	 *   |
	 *   f
	 *  
	 */
	NW((byte)(_N+_W)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i - 1][j].u = cells[i][j].u;
			cells[i][j].v = cells[i][j - 1].v;

		}
		//@formatter:off
	},
	
	/** 
	 * Północ - Wschód
	 * 
	 *   e
	 *   |
	 * f-s-e
	 *   |
	 *   f
	 *  
	 */
	NE((byte)(_N+_E)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].u = cells[i - 1][j].u;
			cells[i][j].v = cells[i][j - 1].v;

		}
		//@formatter:off
	},
	
	/** 
	 * Wschód - Zachód
	 * 
	 *   f
	 *   |
	 * e-s-e
	 *   |
	 *   f
	 *  
	 */
	EW((byte)(_E+_W)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {

			cells[i][j].u += dt * gx;
			cells[i - 1][j].u += dt * gx;

		}
		//@formatter:off
	},
	
	/** 
	 * Północ - Południe
	 * 
	 *   e
	 *   |
	 * f-s-f
	 *   |
	 *   e
	 *  
	 */
	NS((byte)(_N+_S)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].v += dt * gy;
			cells[i][j - 1].v += dt * gy;
		}
		//@formatter:off
	},
	
	/** 
	 * Północ - Południe - Wschód
	 * 
	 *   e
	 *   |
	 * f-s-e
	 *   |
	 *   e
	 *  
	 */
	NSE((byte)(_N+_S+_E)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].v += dt * gy;
			cells[i][j - 1].v += dt * gy;
			cells[i][j].u = cells[i - 1][j].u;
		}
		//@formatter:off
	},
	
	/** 
	 * Południe - Wschód - Zachód
	 * 
	 *   f
	 *   |
	 * e-s-e
	 *   |
	 *   e
	 *  
	 */
	SEW((byte)(_S+_E+_W)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].u += dt * gx;
			cells[i - 1][j].u += dt * gx;
			cells[i][j - 1].v = cells[i][j].v;
		}
		//@formatter:off
	},
	
	/** 
	 * Północ - Południe - Zachód
	 * 
	 *   e
	 *   |
	 * e-s-f
	 *   |
	 *   e
	 *  
	 */
	NSW((byte)(_N+_S+_W)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].v += dt * gy;
			cells[i][j - 1].v += dt * gy;
			cells[i - 1][j].u = cells[i][j].u;
		}
		//@formatter:off
	},
	
	/** 
	 * Północ - Wschód - Zachód
	 * 
	 *   e
	 *   |
	 * e-s-e
	 *   |
	 *   f
	 *  
	 */
	NEW((byte)(_N+_E+_W)) {
		//@formatter:on
		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].u += dt * gx;
			cells[i - 1][j].u += dt * gx;
			cells[i][j].v = cells[i][j - 1].v;
		}
		//@formatter:off
	},
	/** 
	 * Północ - Południe - Wschód - Zachód
	 * 
	 *   e
	 *   |
	 * e-s-e
	 *   |
	 *   e
	 *  
	 */
	//@formatter:on
	NSEW((byte) (_N + _S + _E + _W)) {

		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {
			cells[i][j].u += dt * gx;
			cells[i - 1][j].u += dt * gx;
			cells[i][j].v += dt * gy;
			cells[i][j - 1].v += dt * gy;
		}

	},

	EMPTY((byte) 255) {

		@Override
		public void adjust(int i, int j, Cell[][] cells, double dx, double dy, double dt, double gx, double gy) {

		}

	};

	private final byte id;

	private Surface(byte id) {
		this.id = id;
	}

	public byte getId() {
		return id;
	}

	public static ISurface getInstance(int i, int j, Cell[][] cells) {

		byte flag = 0;

		if (cells[i][j + 1].flag == Flag.EMPTY) {
			flag += _N;
		}

		if (cells[i][j - 1].flag == Flag.EMPTY) {
			flag += _S;
		}

		if (cells[i + 1][j].flag == Flag.EMPTY) {
			flag += _E;
		}

		if (cells[i - 1][j].flag == Flag.EMPTY) {
			flag += _W;
		}

		for (Surface s : values()) {

			if (s.id == flag) {
				return s;
			}

		}

		return EMPTY;

	}

}
